package com.yungu.swift.system.marketing.service.impl;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import com.github.miemiedev.mybatis.paginator.domain.PageBounds;
import com.github.miemiedev.mybatis.paginator.domain.PageList;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.yungu.swift.assets.driver.model.dto.DriverDto;
import com.yungu.swift.assets.driver.service.DriverService;
import com.yungu.swift.assets.passenger.model.dto.PassengerCouponBatchLogDto;
import com.yungu.swift.assets.passenger.model.dto.PassengerCouponDto;
import com.yungu.swift.assets.passenger.model.dto.PassengerDto;
import com.yungu.swift.assets.passenger.service.PassengerCouponBatchLogService;
import com.yungu.swift.assets.passenger.service.PassengerCouponService;
import com.yungu.swift.assets.passenger.service.PassengerService;
import com.yungu.swift.base.ResponseData;
import com.yungu.swift.base.mapper.IMapper;
import com.yungu.swift.base.model.PageVo;
import com.yungu.swift.base.model.config.ServerConfig;
import com.yungu.swift.base.service.impl.BaseServiceImpl;
import com.yungu.swift.common.service.CommonSmsService;
import com.yungu.swift.constants.FinanceConstant;
import com.yungu.swift.constants.MagicConstant;
import com.yungu.swift.system.config.ApplicationConfig;
import com.yungu.swift.system.finance.model.dto.FinanceInviteRewardDto;
import com.yungu.swift.system.finance.service.FinanceInviteRewardService;
import com.yungu.swift.system.marketing.dao.*;
import com.yungu.swift.system.marketing.model.dto.*;
import com.yungu.swift.system.marketing.model.param.AdminCouponGiftHistoryPageParam;
import com.yungu.swift.system.marketing.model.param.AdminCouponGiftParam;
import com.yungu.swift.system.marketing.model.param.AdminCouponParam;
import com.yungu.swift.system.marketing.model.vo.AdminMarketingGiftVo;
import com.yungu.swift.system.marketing.service.MarketingGiftService;
import com.yungu.swift.system.marketing.thread.MarketingGiftCodeThread;
import com.yungu.swift.system.sys.dao.SysAreaMapper;
import com.yungu.swift.system.sys.dao.SysCityMapper;
import com.yungu.swift.system.sys.model.dto.SysAccountDriverDto;
import com.yungu.swift.system.sys.model.dto.SysAccountPlatformDto;
import com.yungu.swift.system.sys.service.SysAccountDriverService;
import com.yungu.swift.system.sys.service.SysAccountPlatformService;
import com.yungu.swift.utils.JsonUtils;
import com.yungu.swift.utils.MapUtils;
import com.yungu.swift.utils.ParamUtil;
import com.yungu.swift.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.map.HashedMap;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cglib.beans.BeanMap;
import org.springframework.transaction.support.TransactionTemplate;

import java.math.BigDecimal;
import java.text.MessageFormat;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;

import static com.yungu.swift.system.config.NacosListener.SYS_CONFIG;
import static com.yungu.swift.system.marketing.model.enums.MarketingErrorEnum.COUNT_LIMIT;
import static com.yungu.swift.system.marketing.model.enums.MarketingErrorEnum.GIFT_NOT_FOUND;

/**
 * <p>
 * 优惠券礼包业务逻辑接口实现类
 *
 * @author xiuyin.cui - Generate
 * @version 1.1.0-SNAPSHOT
 * @since 2019-04-25 13:50
 */
@Slf4j
@Service
public class MarketingGiftServiceImpl extends BaseServiceImpl<MarketingGiftDto> implements MarketingGiftService {

    private final static Integer ONCE_SEND_COUNT = 3000;

    @Autowired
    private MarketingGiftMapper marketingGiftMapper;
    @Autowired
    private MarketingGiftCityMapper marketingGiftCityMapper;
    @Autowired
    private MarketingCouponMapper marketingCouponMapper;
    @Autowired
    private MarketingGiftCodeMapper marketingGiftCodeMapper;
    @Autowired
    private MarketingGiftWillDrawMapper marketingGiftWillDrawMapper;
    @Autowired
    private MarketingGiftDrawlogMapper marketingGiftDrawlogMapper;
    @Autowired
    private MarketingChannelMapper marketingChannelMapper;
    @Autowired
    private MarketingChannelLogMapper marketingChannelLogMapper;
    @Autowired
    private SysCityMapper sysCityMapper;
    @Autowired
    private MarketingCouponTemplateMapper marketingCouponTemplateMapper;
    @Autowired
    private SysAreaMapper sysAreaMapper;
    @Autowired
    private TransactionTemplate transactionTemplate;
    @Reference
    private PassengerCouponBatchLogService passengerCouponBatchLogService;
    @Reference
    private PassengerService passengerService;
    @Reference
    private PassengerCouponService passengerCouponService;
    @Reference
    private DriverService driverService;
    @Reference
    private SysAccountDriverService sysAccountDriverService;
    @Reference
    private SysAccountPlatformService sysAccountPlatformService;
    @Reference
    private FinanceInviteRewardService financeInviteRewardService;
    @Reference
    private CommonSmsService commonSmsService;

    @Override
    protected IMapper<MarketingGiftDto> getMapper() {
        return marketingGiftMapper;
    }

    private final static ExecutorService POOL = new ThreadPoolExecutor(20, 100,
            0L, TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<>(1024),
            new ThreadFactoryBuilder().setNameFormat("coupon-send-pool").build(),
            new ThreadPoolExecutor.CallerRunsPolicy());

    @Override
    public ResponseData<Boolean> saveOrUpdate(AdminCouponGiftParam couponGiftParam, boolean hasChangeCoupon) {
        MarketingGiftDto giftDto = new MarketingGiftDto();
        // 1. 转换属性
        convert(couponGiftParam, giftDto);
        int affectedRowCount = 0;
        // 2. 有 id 则说明是更新
        if (StringUtils.isNotEmpty(giftDto.getUuid())) {
            giftDto.setUpdateOn(new Date());
            giftDto.setUpdateBy(couponGiftParam.getUserUuid());
            // 如果有更新优惠券信息 则要把之前的优惠券设置为失效 并且保存新的优惠券信息
            if (hasChangeCoupon) {
                // 让之前的优惠券失效
                marketingCouponMapper.expiryCouponByGiftUuid(giftDto.getUuid());
                // 更新优惠券信息
                saveGiftCoupon(couponGiftParam.getCouponParams(), couponGiftParam.getUserUuid(), null,
                        giftDto.getUuid());
            }
            affectedRowCount = marketingGiftMapper.edit(giftDto);
        }
        // 3. 无 id 则说明是新增
        if (StringUtils.isEmpty(giftDto.getUuid())) {
            buildGift(giftDto, couponGiftParam);
            // 新增礼包
            affectedRowCount = marketingGiftMapper.add(giftDto);
        }
        // 4. 新增礼包city
        if (affectedRowCount > 0) {
            //删掉之前保存的发放城市
            marketingGiftCityMapper.deleteBatch(giftDto.getUuid());
            if (StringUtils.isNotEmpty(giftDto.getSendCity())) {
                List<MarketingGiftCityDto> list = new ArrayList<>();
                for (String cityUuid : giftDto.getSendCity().split(",")) {
                    MarketingGiftCityDto marketingGiftCityDto = new MarketingGiftCityDto();
                    marketingGiftCityDto.setUuid(StringUtils.buildUUID());
                    marketingGiftCityDto.setAppid(giftDto.getAppid());
                    marketingGiftCityDto.setGiftUuid(giftDto.getUuid());
                    marketingGiftCityDto.setCityUuid(cityUuid);
                    marketingGiftCityDto.setCreateBy(couponGiftParam.getUserUuid());
                    marketingGiftCityDto.setCreateOn(new Date());
                    list.add(marketingGiftCityDto);
                }
                if (CollectionUtils.isNotEmpty(list)) {
                    marketingGiftCityMapper.addBatch(list);
                }
            }
        }
        return ResponseData.buildSuccessResponse("保存礼包成功", Boolean.TRUE);
    }

    /**
     * 属性转换
     *
     * @param source
     * @param target
     */
    private void convert(AdminCouponGiftParam source, MarketingGiftDto target) {
        BeanUtils.copyProperties(source, target);
        if (source.getDriverCashback() != null) {
            target.setDriverCashback(BigDecimal.valueOf(source.getDriverCashback()));
        }
        // 城市信息
        target.setSendCityName("");
        if (StringUtils.isNotEmpty(source.getSendCity())) {
            target.setSendCityName(sysCityMapper.getCityNames(Arrays.asList(source.getSendCity().split(","))));
        }
        //礼包数量信息
        target.setRemainNumber(source.getRemainNumber());
        if (source.getUuid() == null) {
            target.setTotalNumber(source.getRemainNumber());
        }
    }

    /**
     * 新建礼包信息
     *
     * @param giftDto
     * @param couponGiftParam
     */
    private void buildGift(MarketingGiftDto giftDto, AdminCouponGiftParam couponGiftParam) {
        giftDto.setUuid(StringUtils.buildUUID());
        giftDto.setCreateOn(new Date());
        giftDto.setCreateBy(couponGiftParam.getUserUuid());
        giftDto.setStatus(1);
        // 4 只有二维码礼包才设置领取地址
        if (MarketingGiftDto.GIFT_QR_CODE == giftDto.getType()) {
            StringBuilder builder = new StringBuilder();
            builder.append(SYS_CONFIG.getApiHost()).append("/yue/qrCodeView?giftUuid=").append(giftDto.getUuid());
            builder.append("&appid=").append(giftDto.getAppid());
            giftDto.setDrawUrl(builder.toString());
        }
        // 7 兑换码/口令处理
        if (MarketingGiftDto.GIFT_REDEEM_CODE == couponGiftParam.getType() && giftDto.getCodeType() != null) {
            POOL.execute(new MarketingGiftCodeThread(couponGiftParam, giftDto.getUuid(), marketingGiftCodeMapper));
        }
        List<String> passengerUuids = new ArrayList<>();
        // 6 一次性发放处理
        if (MarketingGiftDto.GIFT_ONCE_SEND == giftDto.getType() && couponGiftParam.getSendType() != null) {
            //发放指定用户
            if (couponGiftParam.getSendType() == 0 && StringUtils.isNotEmpty(couponGiftParam.getSendUser())) {
                String[] userMobile = couponGiftParam.getSendUser().split(",");
                giftDto.setSendDate(new Date());
                giftDto.setSendCount(userMobile.length);
                passengerUuids = passengerService.getUuidsByMobiles(userMobile).getData();
            }
            //发送全部用户
            if (couponGiftParam.getSendType() == 1) {
                List<String> cityList = "ALL".equals(couponGiftParam.getSendCity())?new ArrayList<>():Arrays.asList(couponGiftParam
                        .getSendCity().split(","));
                //这边获取用户时根据城市过滤一下
                passengerUuids = passengerService.getUuids(MapUtils.build("sendCityList", cityList)).getData();
                giftDto.setSendDate(new Date());
                giftDto.setSendCount(ParamUtil.defaultIfNull(passengerUuids, Lists.newArrayList()).size());
            }
        }
        // 保存优惠券信息
        saveGiftCoupon(couponGiftParam.getCouponParams(), couponGiftParam.getUserUuid(), passengerUuids, giftDto.getUuid());
        // 新增对应的渠道
        final MarketingChannelDto marketingChannelDto = new MarketingChannelDto();
        marketingChannelDto.setUuid(StringUtils.buildUUID());
        marketingChannelDto.setGiftUuid(giftDto.getUuid());
        marketingChannelDto.setName("默认渠道");
        marketingChannelDto.setAppid(giftDto.getAppid());
        marketingChannelDto.setAgentUuid(giftDto.getAgentUuid());
        marketingChannelDto.setCompanyUuid(giftDto.getCompanyUuid());
        marketingChannelDto.setCreateBy(giftDto.getCreateBy());
        marketingChannelDto.setCreateOn(giftDto.getCreateOn());
        marketingChannelDto.setPreset(1);
        //只有二维码礼包才设置领取地址
        if (MarketingGiftDto.GIFT_QR_CODE == giftDto.getType()) {
            marketingChannelDto.setDrawUrl(giftDto.getDrawUrl() + "&cid=" + marketingChannelDto.getUuid());
        }
        marketingChannelMapper.add(marketingChannelDto);
        // 新增渠道邀请记录
        if (CollectionUtils.isNotEmpty(passengerUuids)) {
            List<MarketingChannelLogDto> marketingChannelLogDtoList = new ArrayList<>();
            final List<String> finalPassengerUuids = passengerUuids;
            POOL.execute(() -> {
                Date now = new Date();
                for (String passengerUuid : finalPassengerUuids) {
                    MarketingChannelLogDto marketingChannelLogDto = new MarketingChannelLogDto();
                    marketingChannelLogDto.setUuid(StringUtils.buildUUID());
                    marketingChannelLogDto.setChannelUuid(marketingChannelDto.getUuid());
                    marketingChannelLogDto.setUserUuid(passengerUuid);
                    marketingChannelLogDto.setAppid(marketingChannelDto.getAppid());
                    marketingChannelLogDto.setAgentUuid(marketingChannelDto.getAgentUuid());
                    marketingChannelLogDto.setCompanyUuid(marketingChannelDto.getCompanyUuid());
                    marketingChannelLogDto.setCreateBy(marketingChannelDto.getCreateBy());
                    marketingChannelLogDto.setCreateOn(now);
                    // 非新用户
                    marketingChannelLogDto.setNewUser(0);
                    marketingChannelLogDtoList.add(marketingChannelLogDto);
                }
                List<List<MarketingChannelLogDto>> lists = groupListByQuantity(marketingChannelLogDtoList, ONCE_SEND_COUNT);
                for (int i = 0; i < lists.size(); i++) {
                    marketingChannelLogMapper.addBatch(lists.get(i));
                }
            });
        }
    }

    /**
     * 保存礼包优惠券
     *
     * @param couponParams   优惠券信息
     * @param userUuid
     * @param passengerUuids
     */
    private void saveGiftCoupon(List<AdminCouponParam> couponParams, String userUuid, List<String> passengerUuids,
                                String giftUuid) {
        //需要保存到数据库中的优惠券对象
        List<MarketingCouponDto> marketingCouponListDo = new ArrayList<>();
        //需要保存到数据库中的乘客优惠券对象
        List<PassengerCouponDto> passengerCouponListDo = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(couponParams)) {
            for (AdminCouponParam couponParam : couponParams) {
                List<MarketingCouponTemplateDto> list = marketingCouponTemplateMapper.list(MapUtils.build("uuid",
                        couponParam.getCouponTemplateUuid()));
                if (CollectionUtils.isEmpty(list)) {
                    continue;
                }
                MarketingCouponTemplateDto templateDto = list.get(0);
                if (templateDto == null) {
                    continue;
                }
                String cityNames = "";
                if (StringUtils.isNotEmpty(couponParam.getCityUuids())) {
                    cityNames = sysCityMapper.getCityNames(Arrays.asList(couponParam.getCityUuids().split(",")));
                }
                MarketingCouponDto marketingCouponDto = new MarketingCouponDto();
                marketingCouponDto.setCouponTemplateUuid(templateDto.getUuid());
                marketingCouponDto.setName(templateDto.getName());
                marketingCouponDto.setType(templateDto.getType());
                marketingCouponDto.setSubType(couponParam.getSubType());
                marketingCouponDto.setStatus(1);
                marketingCouponDto.setMoney(templateDto.getMoney() == null ? null : templateDto.getMoney().doubleValue());
                marketingCouponDto.setAstrict(templateDto.getAstrict() == null ? null : templateDto.getAstrict().doubleValue());
                marketingCouponDto.setDiscount(templateDto.getDiscount() == null ? null : templateDto.getDiscount().doubleValue());
                marketingCouponDto.setUseBusinessType(templateDto.getBusinessType());
                marketingCouponDto.setHighestMoney(templateDto.getHighestMoney() == null ? null : templateDto.getHighestMoney().doubleValue());
                marketingCouponDto.setInstruction(templateDto.getInstruction());
                marketingCouponDto.setCreateOn(new Date());
                marketingCouponDto.setCreateBy(userUuid);
                marketingCouponDto.setAppid(templateDto.getAppid());
                marketingCouponDto.setCouponTemplateUuid(templateDto.getUuid());
                marketingCouponDto.setGiftUuid(giftUuid);
                marketingCouponDto.setCityUuids(couponParam.getCityUuids());
                marketingCouponDto.setCityNames(cityNames);
                marketingCouponDto.setTermType(couponParam.getTermType());
                marketingCouponDto.setUseStartTime(couponParam.getUseStartTime());
                marketingCouponDto.setUseEndTime(couponParam.getUseEndTime());
                marketingCouponDto.setUseExpireTime(couponParam.getUseExpireTime());

                //循环次数 因为可能需要发放多张优惠券
                int j = ParamUtil.defaultIfNull(couponParam.getSendCount(), 0);
                for (int i = 0; i < j; i++) {
                    MarketingCouponDto marketingCouponDtoClone = (MarketingCouponDto) marketingCouponDto.clone();
                    marketingCouponDtoClone.setUuid(StringUtils.buildUUID());
                    // TODO 会成为性能瓶颈
                    marketingCouponDtoClone.setNo(marketingCouponMapper.createNo());
                    marketingCouponListDo.add(marketingCouponDtoClone);
                    if (CollectionUtils.isNotEmpty(passengerUuids)) {
                        for (String passengerUuid : passengerUuids) {
                            PassengerCouponDto passengerCouponDto = new PassengerCouponDto();
                            passengerCouponDto.setUuid(StringUtils.buildUUID());
                            passengerCouponDto.setAppid(marketingCouponDtoClone.getAppid());
                            passengerCouponDto.setStatus(1);
                            passengerCouponDto.setCreateOn(new Date());
                            passengerCouponDto.setCreateBy(userUuid);
                            passengerCouponDto.setPassengerUuid(passengerUuid);
                            passengerCouponDto.setSysCouponUuid(marketingCouponDtoClone.getUuid());
                            passengerCouponDto.setCityNames(cityNames);
                            passengerCouponDto.setCityUuids(marketingCouponDto.getCityUuids());
                            //设置优惠券过期时间
                            setCouponExpireTime(marketingCouponDtoClone, passengerCouponDto);
                            passengerCouponListDo.add(passengerCouponDto);
                        }
                    }
                }
            }
            if (!marketingCouponListDo.isEmpty()) {
                //批量新增优惠券对象
                marketingCouponMapper.addBatch(marketingCouponListDo);
            }
            doSendCouponBatch(passengerCouponListDo, giftUuid);
        }
    }

    /**
     * 根据优惠券设置的有效期类型设置乘客的优惠券有效期。
     * 1、如果优惠券有效期设置的是时间段，则乘客优惠券有效期直接设置对应时间段
     * 2、如果优惠券有效期设置的是获取时间开始几天后，则开始时间为当前时间，结束时间为获取后多少天的0点
     *
     * @param marketingCouponDto
     * @param passengerCouponDto
     */
    private void setCouponExpireTime(MarketingCouponDto marketingCouponDto, PassengerCouponDto passengerCouponDto) {
        //设置优惠券过期时间
        if (MagicConstant.INT_ONE == marketingCouponDto.getTermType()) {
            passengerCouponDto.setUseStartTime(marketingCouponDto.getUseStartTime());
            passengerCouponDto.setUseEndTime(marketingCouponDto.getUseEndTime());
        }
        if (MagicConstant.INT_TWO == marketingCouponDto.getTermType()) {
            Calendar calendar = Calendar.getInstance();
            calendar.set(Calendar.HOUR_OF_DAY, 0);
            calendar.set(Calendar.MINUTE, 0);
            calendar.set(Calendar.SECOND, 0);
            calendar.set(Calendar.MILLISECOND, 0);
            passengerCouponDto.setUseStartTime(calendar.getTime());
            calendar.set(Calendar.HOUR_OF_DAY, 23);
            calendar.set(Calendar.MINUTE, 59);
            calendar.set(Calendar.SECOND, 59);
            calendar.set(Calendar.MILLISECOND, 0);
            calendar.add(Calendar.DATE, marketingCouponDto.getUseExpireTime() - 1);
            passengerCouponDto.setUseEndTime(calendar.getTime());
        }
    }

    /**
     * 批次发送乘客优惠券
     *
     * @param passengerCouponDtoList
     */
    private void doSendCouponBatch(final List<PassengerCouponDto> passengerCouponDtoList, final String giftUuid) {
        if (CollectionUtils.isEmpty(passengerCouponDtoList)) {
            return;
        }
        // dubbo 有限制最大数据传输数，所以这里需要拆分
        List<List<PassengerCouponDto>> groupListByQuantity = groupListByQuantity(passengerCouponDtoList, ONCE_SEND_COUNT);
        POOL.submit(() -> {
            //批量保存乘客优惠券
            for (int i = 0; i < groupListByQuantity.size(); i++) {
                List<PassengerCouponDto> subPassengerCouponDtoList = groupListByQuantity.get(i);
                PassengerCouponBatchLogDto passengerCouponBatchLogDto = new PassengerCouponBatchLogDto();
                passengerCouponBatchLogDto.setUuid(StringUtils.buildUUID());
                passengerCouponBatchLogDto.setCreateOn(new Date());
                passengerCouponBatchLogDto.setSort(i + 1);
                passengerCouponBatchLogDto.setGiftUuid(giftUuid);
                passengerCouponBatchLogDto.setPassengerUuid(subPassengerCouponDtoList.get(0).getPassengerUuid());
                try {
                    passengerCouponBatchLogDto.setContent(JsonUtils.writeJsonStr(subPassengerCouponDtoList));
                    passengerCouponService.addBatch(subPassengerCouponDtoList);
                    passengerCouponBatchLogDto.setStatus(1);
                } catch (Exception e) {
                    passengerCouponBatchLogDto.setStatus(2);
                    log.error("发送失败:uuid:{}", passengerCouponBatchLogDto.getUuid(), e);
                }
                passengerCouponBatchLogService.add(passengerCouponBatchLogDto);
            }
        });
    }

    /**
     * 集合按数量分组
     *
     * @param list
     * @param quantity
     * @param <T>
     * @return
     */
    private <T> List<List<T>> groupListByQuantity(List<T> list, int quantity) {
        if (list == null || list.size() == 0 || quantity < 1) {
            return null;
        }
        List<List<T>> result = new ArrayList<>();
        int size = list.size();
        int count = (size + quantity - 1) / quantity;

        for (int i = 0; i < count; i++) {
            List<T> subList = list.subList(i * quantity, ((i + 1) * quantity > size ? size : quantity * (i + 1)));
            result.add(subList);
        }
        return result;
    }


    @Override
    public ResponseData<Boolean> setStatus(String uuid, Integer status) {
        // 后续需要判断注册和邀请只能启用一个
        if (status == 1) {
            MarketingGiftDto marketingGiftDto = marketingGiftMapper.list(MapUtils.build("uuid", uuid)).get(0);
            if (marketingGiftDto == null) {
                return ResponseData.buildErrorResponse(GIFT_NOT_FOUND.getCode(), GIFT_NOT_FOUND.getMsg(), Boolean.FALSE);
            }
            // 乘客邀请、司机邀请只允许开启一个
            if (marketingGiftDto.getType() == MarketingGiftDto.GIFT_PASSENGER_INVITE || marketingGiftDto.getType() ==
                    MarketingGiftDto.GIFT_DRIVER_INVITE) {
                Map<String, Object> countMap = MapUtils.build(4);
                countMap.put("type", marketingGiftDto.getType());
                countMap.put("status", 1);
                countMap.put("subType", marketingGiftDto.getSubType());
                if (marketingGiftMapper.count(countMap) > 0) {
                    return ResponseData.buildErrorResponse(COUNT_LIMIT.getCode(), COUNT_LIMIT.getMsg(), Boolean.FALSE);
                }
            }
        }
        MarketingGiftDto marketingGiftDto = new MarketingGiftDto();
        marketingGiftDto.setUuid(uuid);
        marketingGiftDto.setStatus(status);
        return ResponseData.buildSuccessResponse(marketingGiftMapper.edit(marketingGiftDto) > 0);
    }


    @Override
    public ResponseData<AdminMarketingGiftVo> detail(String uuid) {
        return ResponseData.buildSuccessResponse(marketingGiftMapper.detail(uuid));
    }

    @Override
    public ResponseData<PageVo<MarketingGiftDto>> historyGiftQueryPage(AdminCouponGiftHistoryPageParam historyPageParam) {
        PageBounds pageBounds = new PageBounds(historyPageParam.getPageNum(), historyPageParam.getPageSize());
        BeanMap beanMap = BeanMap.create(historyPageParam);
        PageList<MarketingGiftDto> pageList = marketingGiftMapper.historyGiftQueryPage(beanMap, pageBounds);
        PageVo<MarketingGiftDto> pageVo = new PageVo(historyPageParam.getPageNum(), historyPageParam.getPageSize(),
                pageList.getPaginator().getTotalCount());
        pageVo.setItems(pageList);
        return ResponseData.buildSuccessResponse(pageVo);
    }

    @Override
    public ResponseData<BigDecimal> getAwardAmount(Integer subType) {
        return ResponseData.buildSuccessResponse(marketingGiftMapper.getAwardAmount(subType));
    }

    @Override
    public ResponseData<Map<String, Object>> drawQrCodeGift(String appid, String passengerUuid, String giftUuid, String cid) {
        return drawQrCodeGift(appid, passengerUuid, giftUuid, cid, false);
    }

    @Override
    public ResponseData<Map<String, Object>> drawQrCodeGift(String appid, String passengerUuid, String giftUuid, String cid, boolean isNewUser) {
        //判断该用户是否达到领取上限了
        boolean isUpperLimit = marketingGiftMapper.isUpperLimit(giftUuid, passengerUuid);
        //如果没达到上限 则可以继续领取
        if (!isUpperLimit) {
            MarketingGiftDto marketingGiftDto = new MarketingGiftDto();
            marketingGiftDto.setUuid(giftUuid);
            //领取二维码礼包
            log.info("参数:{}--{}--{}--{}--{}",marketingGiftDto.getGetMode(),marketingGiftDto.getSubType(),marketingGiftDto.getType(),marketingGiftDto.getSendCity(),marketingGiftDto.getUuid());
            List<MarketingCouponDto> qrCodeCouponList = marketingCouponMapper.getActiveCouponsByGift(marketingGiftDto);
            List<PassengerCouponDto> passengerCouponDtoList = new ArrayList<>();
            PassengerCouponDto passengerCouponDto;
            BigDecimal couponMoney = new BigDecimal(0);
            for (MarketingCouponDto marketingCouponDto : qrCodeCouponList) {
                passengerCouponDto = new PassengerCouponDto();
                passengerCouponDto.setUuid(StringUtils.buildUUID());
                passengerCouponDto.setAppid(appid);
                passengerCouponDto.setStatus(1);
                passengerCouponDto.setCreateOn(new Date());
                passengerCouponDto.setPassengerUuid(passengerUuid);
                passengerCouponDto.setSysCouponUuid(marketingCouponDto.getUuid());
                passengerCouponDto.setCityNames(marketingCouponDto.getCityNames());
                passengerCouponDto.setCityUuids(marketingCouponDto.getCityUuids());
                //设置优惠券过期时间
                setCouponExpireTime(marketingCouponDto, passengerCouponDto);
                passengerCouponDtoList.add(passengerCouponDto);
                // 满减
                if (1 == marketingCouponDto.getType()) {
                    couponMoney = couponMoney.add(new BigDecimal(marketingCouponDto.getMoney()));
                    // 折扣	则取最高抵扣
                } else if (2 == marketingCouponDto.getType()) {
                    couponMoney = couponMoney.add(new BigDecimal(marketingCouponDto.getHighestMoney()));
                }
            }
            //批量保存乘客优惠券
            if (!passengerCouponDtoList.isEmpty()) {
                //批量新增乘客优惠券
                passengerCouponService.addBatch(passengerCouponDtoList);
            }
            // 如果找不到对应的优惠券 则提示领取失败
            if (qrCodeCouponList.isEmpty()) {
                return ResponseData.buildErrorResponse(GIFT_NOT_FOUND.getCode(), GIFT_NOT_FOUND.getMsg());
            }
            // 减少二维码礼包数量 并记录礼包领取记录
            Map<String, Object> giftParams = MapUtils.build(8);
            giftParams.put("uuid", giftUuid);
            giftParams.put("status", 1);
            setGiftRemainNumberSub(giftParams, 1);

            MarketingGiftDrawlogDto marketingGiftDrawlogDto = new MarketingGiftDrawlogDto();
            marketingGiftDrawlogDto.setUuid(StringUtils.buildUUID());
            marketingGiftDrawlogDto.setAppid(appid);
            marketingGiftDrawlogDto.setPassengerUuid(passengerUuid);
            marketingGiftDrawlogDto.setGiftUuid(giftUuid);
            marketingGiftDrawlogDto.setCreateBy(passengerUuid);
            marketingGiftDrawlogDto.setCreateOn(new Date());
            marketingGiftDrawlogMapper.add(marketingGiftDrawlogDto);

            ResponseData<PassengerDto> responseData = passengerService.get(MapUtils.build("uuid", passengerUuid));
            if (responseData.isSuccess() && responseData.getData() != null) {
                PassengerDto passengerDto = responseData.getData();
                String channelUuid;
                if (StringUtils.isNotEmpty(cid)) {
                    channelUuid = cid;
                } else {
                    channelUuid = marketingChannelMapper.findChannelUuidByConditions(MapUtils.build("giftUuid", giftUuid));
                }
                // 记录渠道号
                if (StringUtils.isNotEmpty(channelUuid)) {
                    // 记录渠道邀请日志
                    MarketingChannelLogDto marketingChannelLogDto = new MarketingChannelLogDto();
                    marketingChannelLogDto.setUuid(StringUtils.buildUUID());
                    marketingChannelLogDto.setChannelUuid(channelUuid);
                    marketingChannelLogDto.setUserUuid(passengerDto.getUuid());
                    marketingChannelLogDto.setAppid(passengerDto.getAppid());
                    marketingChannelLogDto.setCreateOn(new Date());
                    // 新用户
                    marketingChannelLogDto.setNewUser(isNewUser ? 1 : 0);
                    marketingChannelLogMapper.add(marketingChannelLogDto);
                }
            }
            return ResponseData.buildSuccessResponse("领取礼包成功", MapUtils.build("couponMoney", couponMoney));

        } else {
            return ResponseData.buildErrorResponse(COUNT_LIMIT.getCode(), COUNT_LIMIT.getMsg());
        }
    }

    @Override
    public ResponseData<Boolean> sendAppointGift(List<String> passengerUuids, Integer getMode) {
        log.info("自动指定人群，发放优惠券开始，getMode：{}", getMode);
        MarketingGiftDto marketingGiftParam = new MarketingGiftDto();
        // 自动指定人群
        marketingGiftParam.setType(5);
        marketingGiftParam.setGetMode(getMode);
        // 获得礼包
        MarketingGiftDto marketingGiftDto = marketingGiftMapper.getInfoByDto(marketingGiftParam);
        if (marketingGiftDto == null) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "查询不到相关礼包");
        }
        // 如果需要领取的数量大于库存量 则截取发放列表
        if (passengerUuids.size() > marketingGiftDto.getRemainNumber()) {
            passengerUuids = passengerUuids.subList(0, marketingGiftDto.getRemainNumber());
        }
        final List<String> pasUuids = Lists.newArrayList(passengerUuids);
        // 获取优惠券
        marketingGiftDto.setSendCity(null);
        List<MarketingCouponDto> qrCodeCouponList = marketingCouponMapper.getActiveCouponsByGift(marketingGiftDto);
        List<PassengerCouponDto> passengerCouponDtoList = new ArrayList<>();
        //用来存储用户优惠券数据 需要重复使用 重复设值
        PassengerCouponDto passengerCouponDto = new PassengerCouponDto();
        for (MarketingCouponDto marketingCouponDto : qrCodeCouponList) {
            passengerCouponDto.setAppid(marketingCouponDto.getAppid());
            passengerCouponDto.setStatus(1);
            passengerCouponDto.setCreateOn(new Date());
            passengerCouponDto.setSysCouponUuid(marketingCouponDto.getUuid());
            //设置优惠券过期时间
            setCouponExpireTime(marketingCouponDto, passengerCouponDto);
            for (String passengerUuid : pasUuids) {
                PassengerCouponDto clonePassengerCouponDto = passengerCouponDto.clone();
                clonePassengerCouponDto.setPassengerUuid(passengerUuid);
                clonePassengerCouponDto.setUuid(StringUtils.buildUUID());
                passengerCouponDtoList.add(clonePassengerCouponDto);
            }
        }
        doSendCouponBatch(passengerCouponDtoList, marketingGiftDto.getUuid());
        // 1. 减少礼包数量
        Map<String, Object> giftParams = MapUtils.build(8);
        if (StringUtils.isNotEmpty(marketingGiftDto.getUuid())) {
            giftParams.put("uuid", marketingGiftDto.getUuid());
        }
        if (marketingGiftDto.getGetMode() != null) {
            giftParams.put("getMode", marketingGiftDto.getGetMode());
        }
        if (marketingGiftDto.getType() != null) {
            giftParams.put("type", marketingGiftDto.getType());
        }
        giftParams.put("status", 1);
        CompletableFuture.runAsync(() -> setGiftRemainNumberSub(giftParams, pasUuids.size()));
        // 2. 修改用户为已领取礼包
        CompletableFuture.runAsync(() -> marketingGiftWillDrawMapper.updateStatusByGetMode(1, getMode), POOL)
                .whenCompleteAsync((v, throwable) -> log.info("修改用户为已领取礼包成功，getMode：{}", getMode));
        // 3. 发送短信
        CompletableFuture.runAsync(() -> sendGiftMsg(getMode, pasUuids), POOL)
                .whenCompleteAsync((v, throwable) -> log.info("自动发放人群, getMode:{} 发送短信成功", getMode));
        // 4. 记录渠道
        Map<String, Object> findChannelUuidParams = MapUtils.build();
        // 沉睡用户
        if (getMode == MagicConstant.INT_THREE) {
            findChannelUuidParams.put("type", 5);
        }
        // 高频用户
        if (getMode == MagicConstant.INT_FOUR) {
            findChannelUuidParams.put("type", 6);
        }
        // 连续叫单不成功用户
        if (getMode == MagicConstant.INT_FIVE) {
            findChannelUuidParams.put("type", 7);
        }
        // 获取自动指定人群礼包渠道id
        String channelUuid = marketingChannelMapper.findChannelUuidByConditions(findChannelUuidParams);
        // 记录渠道号
        if (StringUtils.isNotEmpty(channelUuid)) {
            MarketingChannelDto channelDto = marketingChannelMapper.list(MapUtils.build("uuid", channelUuid)).get(0);
            final List<MarketingChannelLogDto> marketingChannelLogDtoList = new ArrayList<>();
            for (String passengerUuid : passengerUuids) {
                // 记录渠道邀请日志
                MarketingChannelLogDto marketingChannelLogDto = new MarketingChannelLogDto();
                marketingChannelLogDto.setUuid(StringUtils.buildUUID());
                marketingChannelLogDto.setChannelUuid(channelUuid);
                marketingChannelLogDto.setUserUuid(passengerUuid);
                marketingChannelLogDto.setAppid(channelDto.getAppid());
                marketingChannelLogDto.setCreateOn(new Date());
                marketingChannelLogDto.setCompanyUuid(channelDto.getCompanyUuid());
                marketingChannelLogDto.setAgentUuid(channelDto.getAgentUuid());
                // 非新用户
                marketingChannelLogDto.setNewUser(0);
                marketingChannelLogDtoList.add(marketingChannelLogDto);
            }
            // 记录渠道日志
            if (!marketingChannelLogDtoList.isEmpty()) {
                List<List<MarketingChannelLogDto>> lists = groupListByQuantity(marketingChannelLogDtoList, ONCE_SEND_COUNT);
                for (int i = 0; i < lists.size(); i++) {
                    marketingChannelLogMapper.addBatch(lists.get(i));
                }
            }
        }
        log.info("自动指定人群，发放优惠券结束，getMode：{}", getMode);
        return ResponseData.buildSuccessResponse("领取礼包成功", Boolean.TRUE);
    }

    private void sendGiftMsg(Integer getMode, List<String> passengerUuids) {
        log.info("getMode:{}, 开始发送优惠券短信。", getMode);
        // 获取优惠券金额
        final BigDecimal couponMoney = marketingCouponMapper.getSumMoneyByTypes(Lists.newArrayList(5), getMode);
        if (couponMoney == null) {
            return;
        }
        // 获得发送乘客
        final List<PassengerDto> passengerDtos = passengerService.getPassengerByUuids(passengerUuids).getData();
        if (CollectionUtils.isEmpty(passengerDtos)) {
            return;
        }
        // 142 的号码不发营销短信
        final List<String> mobiles = passengerDtos.stream().parallel().map(passengerDto -> passengerDto.getMobile())
                .filter(mobile -> mobile.startsWith("142")).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(mobiles)) {
            return;
        }
        // 得到短信模板
        String appid = passengerDtos.get(0).getAppid();
        ServerConfig.SystemBean system = ApplicationConfig.SERVER_CONFIG.getSystem();
        String messagePattern = "";
        if (getMode == 3) {
            messagePattern = system.getSleepPassengerMsg();
        }
        if (getMode == 4) {
            messagePattern = system.getOrderHighMsg();
        }
        if (getMode == 5) {
            messagePattern = system.getOrderFailMsg();
        }
        if (StringUtils.isEmpty(messagePattern)) {
            return;
        }
        for (String mobile : mobiles) {
            commonSmsService.sendCommon(mobile, MessageFormat.format(messagePattern, couponMoney), appid);
        }
    }

    @Override
    public void drawDriverInviteDriverGift(String mobile, String inviteLogUuid) {
        if (mobile == null) {
            log.warn("司机邀请司机奖励，获取不到邀请人信息：{}", mobile);
            return;
        }
        ResponseData<DriverDto> responseData = driverService.get(MapUtils.build("mobile", mobile));
        if (!responseData.isSuccess() || responseData.getData() == null) {
            log.warn("司机邀请司机奖励，获取不到司机信息：{}", mobile);
            return;
        }
        DriverDto driverDto = responseData.getData();
        // 获取司机邀请司机礼包信息
        ResponseData<SysAccountPlatformDto> platformResponse = sysAccountPlatformService.getByAppid(driverDto.getAppid());
        if (!platformResponse.isSuccess() || platformResponse.getData() == null) {
            log.warn("获取不到平台账户信息，appid:{}", driverDto.getAppid());
        }
        SysAccountPlatformDto accountPlatform = platformResponse.getData();
        BigDecimal cashBalance = Optional.ofNullable(accountPlatform.getCashBalance()).orElse(BigDecimal.ZERO);

        ResponseData<SysAccountDriverDto> driverResponse = sysAccountDriverService.get(driverDto.getUuid());
        if (!driverResponse.isSuccess() || driverResponse.getData() == null) {
            log.warn("获取不到司机账户信息，uuid:{}", driverDto.getUuid());
        }
        SysAccountDriverDto accountDriver = driverResponse.getData();
        BigDecimal canFrowardBalance = Optional.ofNullable(accountDriver.getCanFrowardBalance()).orElse(BigDecimal.ZERO);

        // 获取司机邀请司机返现金额
        BigDecimal driverCashback = marketingGiftMapper.getAwardAmount(2);

        //增加司机邀请奖励流水
        FinanceInviteRewardDto inviteRewardDto = new FinanceInviteRewardDto();
        inviteRewardDto.setUuid(StringUtils.buildUUID());
        inviteRewardDto.setAppid(driverDto.getAppid());
        inviteRewardDto.setCourse(FinanceConstant.DRIVER_INVITE_DRIVER_INVITE_REWARD);
        inviteRewardDto.setAmount(driverCashback);
        inviteRewardDto.setBusinessUuid(inviteLogUuid);
        inviteRewardDto.setDescription("司机邀请司机获得" + driverCashback + "元奖励");
        // 平台-> 司机
        inviteRewardDto.setFinanceInflow(driverDto.getUuid());
        inviteRewardDto.setFinanceOutflow(accountPlatform.getUuid());
        inviteRewardDto.setFinanceNumber(StringUtils.buildUUID());
        inviteRewardDto.setStartBalance(canFrowardBalance);
        canFrowardBalance = canFrowardBalance.add(driverCashback);
        inviteRewardDto.setFinalBalance(canFrowardBalance);
        inviteRewardDto.setCreateOn(new Date());
        inviteRewardDto.setCreateBy(driverDto.getUuid());
        financeInviteRewardService.add(inviteRewardDto);

        //修改邀请司机的可提现余额

        accountDriver.setCanFrowardBalance(canFrowardBalance);
        accountDriver.setUpdateOn(new Date());

        //修改平台奖励累积
        cashBalance = cashBalance.add(driverCashback);
        accountPlatform.setRewardAccumulate(cashBalance);
        accountPlatform.setUpdateOn(new Date());

        transactionTemplate.execute(transactionStatus -> {
            sysAccountDriverService.edit(accountDriver);
            sysAccountPlatformService.edit(accountPlatform);
            return Boolean.TRUE;
        });
        log.info("司机邀请司机获取奖励处理成功,邀请人信息：{}", mobile);
    }


    /**
     * 根据条件获取查询出的礼包 并设置减少量 来设置剩余礼包数量
     *
     * @param queryParams
     * @param number
     * @return 返回统计返现金额
     */
    private void setGiftRemainNumberSub(Map queryParams, Integer number) {
        //限制查询剩余数量大于0
        queryParams.put("hasRemain", 1);
        List<MarketingGiftDto> marketingGiftDtoList = marketingGiftMapper.list(queryParams);
        for (MarketingGiftDto marketingGiftDto : marketingGiftDtoList) {
            // 只有注册人才会获取到礼包 所以数量减1
            MarketingGiftDto upGiftDto = new MarketingGiftDto();
            upGiftDto.setUuid(marketingGiftDto.getUuid());
            upGiftDto.setRemainNumber(marketingGiftDto.getRemainNumber() - number);
            marketingGiftMapper.edit(upGiftDto);
        }
    }

    @Override
    public ResponseData<MarketingGiftDto> findGiftByMap(Map<String, Object> map) {
        return ResponseData.buildSuccessResponse(marketingGiftMapper.findGiftByMap(map));
    }

    @Override
    public ResponseData<Map<String, Boolean>> isOpenCity(String adCode, Integer type) {
        Map data = new HashedMap();
        MarketingGiftDto marketingGiftDto = marketingGiftMapper.findCityByType(type);
        //判断类型下优惠券礼包是否开通
        if (marketingGiftDto != null) {
            //判断发放城市是否为全国
            if (marketingGiftDto.getSendCity() == null || "".equals(marketingGiftDto.getSendCity())) {
                data.put("result", true);
            } else {
                String areaUuid = sysAreaMapper.getAreaUuidByAdCode(adCode);
                if (marketingGiftMapper.isOpenCity(areaUuid, type)) {
                    data.put("result", true);
                } else {
                    String cityUuid = sysCityMapper.getCityUuidByAdCode(adCode);
                    if (marketingGiftMapper.isOpenCity(cityUuid, type)) {
                        data.put("result", true);
                    } else {
                        data.put("result", false);
                    }
                }
            }
        } else {
            data.put("result", false);
        }
        return ResponseData.buildSuccessResponse(data);
    }
}